package xyz.labmem.base.core.error

import cn.dev33.satoken.exception.NotLoginException
import cn.dev33.satoken.exception.NotPermissionException
import cn.dev33.satoken.exception.SaTokenException
import cn.hutool.core.util.ReflectUtil
import cn.hutool.core.util.StrUtil
import com.alibaba.excel.exception.ExcelDataConvertException
import io.swagger.annotations.ApiModelProperty
import org.springframework.dao.DataIntegrityViolationException
import org.springframework.http.HttpStatus
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.jdbc.BadSqlGrammarException
import org.springframework.validation.BindingResult
import org.springframework.validation.FieldError
import org.springframework.validation.ObjectError
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException
import xyz.labmem.base.core.consts.log
import xyz.labmem.base.core.result.FORMVERIFY_CODE
import xyz.labmem.base.core.result.RU
import xyz.labmem.base.core.result.RV
import java.util.function.Consumer
import javax.servlet.http.HttpServletRequest

/**
 * 异常捕获
 * @Author lty
 * @Date 2021/12/15 9:33
 */
@ControllerAdvice
class CaptureException {

    /**
     * 全局异常捕捉处理
     * @param ex
     * @return
     */
    @ExceptionHandler(value = [Exception::class])
    @ResponseStatus(HttpStatus.OK)//使http返回的状态码是200
    @ResponseBody
    fun allExceptionHandler(ex: Exception, request: HttpServletRequest): RV<Any> {
        if (ex is HttpMessageNotReadableException && ex.message!!.indexOf("JSON parse") >= 0) {
            return RU.failed("入参格式错误！", ex.message)
        }
        when (ex) {
            is HttpMessageNotReadableException -> return RU.failed("无效参数！", ex.message)
            is MethodArgumentTypeMismatchException -> return RU.failed("参数类型错误！", ex.message)
            is ExcelDataConvertException -> return RU.failed("Excel 数据格式有误！", ex.message)
            is DataIntegrityViolationException -> {
                if (ex.message!!.indexOf("Out of range value for column 'longitude' at row 1") >= 0) {
                    return RU.failed("数据经度错误！", ex.message)
                } else if (ex.message!!.indexOf("Out of range value for column 'latitude' at row 1") >= 0) {
                    return RU.failed("数据纬度错误！", ex.message)
                }
            }
            is BadSqlGrammarException -> {
                ex.cause?.let {
                    return RU.failed("sql执行错误！", it.message)
                }
            }
        }
        ex.printStackTrace()
        return RU.failed("服务器错误！请叫程序猿修bug", ex.message)
    }

    /**
     * saToken异常捕捉处理
     * @param ex
     * @return
     */
    @ExceptionHandler(value = [SaTokenException::class])
    @ResponseStatus(HttpStatus.OK)//使http返回的状态码是200
    @ResponseBody
    fun saTokenExceptionHandler(ex: SaTokenException, request: HttpServletRequest): RV<Any> {
        val log = ex.log()
        return when (ex) {
            is NotLoginException -> if(ex.type.equals("-1")){RU.notPassword("账号或密码错误")}else{RU.notLogin(ex.message)}
            is NotPermissionException -> RU.authError("无权操作！")
            else -> {
                log.error(ex.localizedMessage)
                RU.failedMsg(ex.message)
            }
        }
    }

    /**
     * 入参验证异常捕捉处理
     * @param ex
     * @return
     */
    @ExceptionHandler(value = [MethodArgumentNotValidException::class])
    @ResponseStatus(HttpStatus.OK)//使http返回的状态码是200
    @ResponseBody
    fun methodArgumentNotValidExceptionHandler(
        ex: MethodArgumentNotValidException,
        request: HttpServletRequest
    ): RV<*> {
        val result: BindingResult = ex.bindingResult
        return if (result.hasErrors()) {
            val allErrors = result.allErrors
            val validMsgs = ArrayList<String>()
            allErrors.forEach(Consumer { objectError: ObjectError ->
                val fieldError = objectError as FieldError
                try {
                    val source = ReflectUtil.getFieldValue(fieldError, "source")
                    val been = ReflectUtil.getFieldValue(source, "rootBean").javaClass
                    try {
                        val field = been.getDeclaredField(fieldError.field)
                        val apiModelProperty = field.getAnnotation(ApiModelProperty::class.java)
                        if (apiModelProperty != null && StrUtil.isNotBlank(apiModelProperty.value)) {
                            validMsgs.add("${apiModelProperty.value}[${fieldError.field}] ${fieldError.defaultMessage}")
                        } else
                            validMsgs.add("[${fieldError.field}] ${fieldError.defaultMessage}")
                    } catch (e: Exception) {
                        validMsgs.add("[${fieldError.field}] ${fieldError.defaultMessage}")
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    validMsgs.add("[${fieldError.field}] ${fieldError.defaultMessage}")
                }
            })
            RU.free(FORMVERIFY_CODE, "表单验证失败", validMsgs)
        } else
            RU.free(FORMVERIFY_CODE, "表单验证失败", null)
    }


}